package com.lexaden.platform.web;

import java.util.LinkedHashMap;
import java.util.Map;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

import com.vaadin.server.VaadinSession;
import com.vaadin.ui.UI;

public class ApplicationScope implements Scope, DisposableBean {
	public static final String NAME = "applicationScope";
	private static final String APPLICATION_SCOPE = NAME + ".";
	private final Map<String, Runnable> destructionCallbacks = new LinkedHashMap<String, Runnable>();

	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {

		final VaadinSession current = VaadinSession.getCurrent();
		String uiId = getCurrentUiId();
		Object bean = current.getAttribute(APPLICATION_SCOPE + uiId + name);
		if (bean == null) {
			bean = objectFactory.getObject();
			current.setAttribute(APPLICATION_SCOPE + uiId + name, bean);
		}
		return bean;
	}

	@Override
	public Object remove(String name) {
		System.out.println("ApplicationScope.remove()");
		final VaadinSession current = VaadinSession.getCurrent();

		String uiId = getCurrentUiId();
		Object bean = current.getAttribute(APPLICATION_SCOPE + uiId + name);
		if (bean != null) {
			current.setAttribute(APPLICATION_SCOPE + uiId + name, null);
			this.destructionCallbacks.remove(name);
		}
		return bean;
	}

	private String getCurrentUiId() {
		final UI currentUI = UI.getCurrent();
		String uiId;
		if (currentUI == null || currentUI.getUIId() == -1l) {
			uiId = VaadinSession.getCurrent()
					.getAttribute("applicationScope.UiId").toString();

		} else {
			uiId = currentUI.getUIId() + "";
		}
		return uiId;
	}

	@Override
	public void registerDestructionCallback(String name, Runnable callback) {
		this.destructionCallbacks.put(name, callback);
	}

	@Override
	public Object resolveContextualObject(String key) {
		return null;
	}

	@Override
	public String getConversationId() {
		return null;
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("ApplicationScope.destroy()");
		
		for (Runnable runnable : this.destructionCallbacks.values()) {
			runnable.run();
		}
		this.destructionCallbacks.clear();
	}
}